unit ec_showchoices;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, Buttons,
  StdCtrls, ec_base, fpjson;

type

  { TECShowChoicesFrame }

  TECShowChoicesFrame = class(TECBaseFrame)
    BackgroundComboBox: TComboBox;
    BackgroundLabel: TLabel;
    BackgroundPanel: TPanel;
    Choice1Edit: TEdit;
    Choice1Label: TLabel;
    Choice1Panel: TPanel;
    Choice2Edit: TEdit;
    Choice2Label: TLabel;
    Choice2Panel: TPanel;
    Choice3Edit: TEdit;
    Choice3Label: TLabel;
    Choice3Panel: TPanel;
    Choice4Edit: TEdit;
    Choice4Label: TLabel;
    Choice4Panel: TPanel;
    Choice5Edit: TEdit;
    Choice5Label: TLabel;
    Choice5Panel: TPanel;
    Choice6Edit: TEdit;
    Choice6Label: TLabel;
    Choice6Panel: TPanel;
    ChoicesGroupBox: TGroupBox;
    PositionComboBox: TComboBox;
    DefaultComboBox: TComboBox;
    CancellationComboBox: TComboBox;
    PositionLabel: TLabel;
    DefaultLabel: TLabel;
    CancellationLabel: TLabel;
    PositionPanel: TPanel;
    DefaultPanel: TPanel;
    CancellationPanel: TPanel;
    ChoicesScrollBox: TScrollBox;
    SettingsGroupBox: TGroupBox;
    ShowChoicesMainPanel: TPanel;
    ChoiceSettingSplitter: TSplitter;
  private
    function GetEdit(Index: Integer): TEdit;
    function GetChoiceText(Index: Integer): String;

    procedure InitialSetUp;
  public
    procedure InitNew; override;
    procedure InitExisting; override;
    procedure MakeResultingCommand; override;
  end;

var
  ECShowChoicesFrame: TECShowChoicesFrame;

implementation

uses
  comboboxhelper, constants;

{$R *.lfm}

resourcestring
  rsChoiceNumber = 'Choice #%d';
  rsOwnCancelBranch = 'Own branch';
  rsCancelDisabled = 'Disabled';
  rsNoDefaultBranch = 'None';

{ TECShowChoicesFrame }

function TECShowChoicesFrame.GetEdit(Index: Integer): TEdit;
begin
  case Index of
    1: GetEdit := Choice1Edit;
    2: GetEdit := Choice2Edit;
    3: GetEdit := Choice3Edit;
    4: GetEdit := Choice4Edit;
    5: GetEdit := Choice5Edit;
    6: GetEdit := Choice6Edit;
  else
    GetEdit := nil;
  end;
end;

function TECShowChoicesFrame.GetChoiceText(Index: Integer): String;
var
  ChoiceEdit: TEdit;
begin
  ChoiceEdit := GetEdit(Index);
  GetChoiceText := ChoiceEdit.Text;
end;

procedure TECShowChoicesFrame.InitialSetUp;
  procedure FillOnCancel;
  var
    I: Integer;
  begin
    with CancellationComboBox.Items do begin
      BeginUpdate;
        Clear;
        Add(rsOwnCancelBranch);
        Add(rsCancelDisabled);
        for I := 1 to 6 do begin
            Add(rsChoiceNumber.Format([I]));
        end;

      EndUpdate;
    end;
  end;

  procedure FillDefault;
  var
    I: Integer;
  begin
    with DefaultComboBox.Items do begin
      BeginUpdate;
        Clear;
        Add(rsNoDefaultBranch);
        for I := 1 to 6 do begin
            Add(rsChoiceNumber.Format([I]));
        end;

      EndUpdate;
    end;
  end;

begin
  FillMessageBgTypeCombobox(BackgroundComboBox);
  FillChoicePosCombobox(PositionComboBox);
  FillDefault;
  FillOnCancel;
end;

procedure TECShowChoicesFrame.InitNew;
begin
  InitialSetUp;

  BackgroundComboBox.ItemIndex := 0;
  PositionComboBox.ItemIndex := 2;
  DefaultComboBox.ItemIndex := 1;
  CancellationComboBox.ItemIndex := 3;

  Choice1Edit.Text := rsYes;
  Choice2Edit.Text := rsNo;
end;

procedure TECShowChoicesFrame.InitExisting;
var
  Params: TJSONArray;

  procedure SetChoiceTexts;
  var
    I: Integer;
    ChoiceTexts: TJSONArray;
    Edit: TEdit;
  begin
    if (Params.Count < 1) or (Params[0].JSONType <> jtArray) then
      Exit;

    ChoiceTexts := Params.Arrays[0];

    for I := 0 to ChoiceTexts.Count -1 do
      if ChoiceTexts[I].JSONType = jtString then begin
        Edit := GetEdit(I + 1);
        Edit.Text := ChoiceTexts.Strings[I];
      end;
  end;

  procedure SetUpSettings;
    procedure SingleParam(I: Integer; CBox: TComboBox; Shift: Integer = 0);
    var
      Value: Integer = 0;
    begin
      if (Params <> nil) and (Params.Count > I)
                            and (Params[I].JSONType = jtNumber) then
        Value := Params.Integers[I];

      CBox.ItemIndex := Value + Shift;
    end;

  begin
    SingleParam(1, CancellationComboBox, 2);
    SingleParam(2, DefaultComboBox, 1);
    SingleParam(3, PositionComboBox);
    SingleParam(4, BackgroundComboBox);
  end;

begin
  InitialSetUp;
  Params := GetFirstParams;

  if Params <> nil then begin
    SetChoiceTexts;
    SetUpSettings
  end else
    InitNew;
end;

procedure TECShowChoicesFrame.MakeResultingCommand;
var
  NumChoices: Integer;

  procedure CountChoices;
  begin
    NumChoices := 6;
    while NumChoices >= 1 do begin
      if Trim(GetChoiceText(NumChoices)) = '' then
        Dec(NumChoices)
      else
        Break;
    end;
  end;

  function FirstCommand: TJSONObject;
    function GetChoiceTexts: TJSONArray;
    var
      ChoiceTexts: TJSONArray;
      I: Integer;
    begin
      ChoiceTexts := TJSONArray.Create;
      for I := 1 to NumChoices do
        ChoiceTexts.Add(GetChoiceText(I));
      GetChoiceTexts := ChoiceTexts;
    end;

  begin

    FirstCommand := TJSONObject.Create([
      'code', SHOW_CHOICES_START_EC_CODE,
      'indent', Indent,
      'parameters', TJSONArray.Create([
                                       GetChoiceTexts,
                                       CancellationComboBox.ItemIndex - 2,
                                       DefaultComboBox.ItemIndex - 1,
                                       PositionComboBox.ItemIndex,
                                       BackgroundComboBox.ItemIndex
                    ])
    ]);
  end;

  procedure AddEmptyCommand;
  begin
    ResultingCommand.Add(TJSONObject.Create([
      'code', 0,
      'indent', Indent + 1,
      'parameters', TJSONArray.Create()
    ]));
  end;

  procedure AddExitingSubCommands(IsCancel: Boolean; Index: Integer = -1);
  var
    CodeToFind: Integer = SHOW_CHOICES_BRANCH_EC_CODE;
    IndexToFind: Integer;
    Start: Integer;

    function FindStart: Integer;
    var
      I: Integer;
      Cmd: TJSONObject;
    begin
      I := ListIndex + 1;
      while I < EcList.Count do begin
        Cmd := EcList.Objects[I];
        if (Cmd.Integers['code'] = CodeToFind) and
              (Cmd.Arrays['parameters'].Integers[0] = IndexToFind) and
              (Cmd.Integers['indent'] = Indent) then begin
          Exit(I + 1);
        end;

        Inc(I);
      end;

      Exit(-1);
    end;

    procedure AddCommandsFromStart;
    var
      I: Integer;
      Cmd: TJSONObject;
    begin
      I := Start;
      while I < EcList.Count do begin
        Cmd := EcList.Objects[I];

        if Cmd.Integers['indent'] <= Indent then
          Break
        else
          ResultingCommand.Add(Cmd.Clone);

        Inc(I)
      end;

    end;

  begin
    if IsCancel then begin
      CodeToFind := SHOW_CHOICES_CANCEL_BRANCH_EC_CODE;
      IndexToFind := 6;
    end else begin
      CodeToFind := SHOW_CHOICES_BRANCH_EC_CODE;
      IndexToFind := Index - 1; {JSON indexes are zero-based}
    end;

    Start := FindStart;
    if Start = -1 then
      AddEmptyCommand
    else
      AddCommandsFromStart;
  end;

  procedure AddBranchCommands(Index: Integer);
  begin
    ResultingCommand.Add(TJSONObject.Create([
      'code', SHOW_CHOICES_BRANCH_EC_CODE,
      'indent', Indent,
      'parameters', TJSONArray.Create([
        Index - 1,
        GetChoiceText(Index)
      ])
    ]));

    if EcList <> nil then
      AddExitingSubCommands(False, Index)
    else
      AddEmptyCommand;
  end;

  procedure AddCancelCommands;
  begin
    ResultingCommand.Add(TJSONObject.Create([
      'code', SHOW_CHOICES_CANCEL_BRANCH_EC_CODE,
      'indent', Indent,
      'parameters', TJSONArray.Create([
        6,
        nil
      ])
    ]));

    if EcList <> nil then
      AddExitingSubCommands(True)
    else
      AddEmptyCommand;
  end;

  procedure AddEndCommand;
  begin
    ResultingCommand.Add(TJSONObject.Create([
      'code', SHOW_CHOICES_END_EC_CODE,
      'indent', Indent,
      'parameters', TJSONArray.Create()
    ]));
  end;

var
  I: Integer;
begin
  CountChoices;

  ResultingCommand := TJSONArray.Create();
  ResultingCommand.Add(FirstCommand);

  for I := 1 to NumChoices do
    AddBranchCommands(I);

  if CancellationComboBox.ItemIndex = 0 then
    AddCancelCommands;

  AddEndCommand;
end;

end.

